﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;

namespace PruebaDllLua
{
    class Program
    {
        static Dictionary<string, Lua.lua_CFunction> funciones =
            new Dictionary<string, Lua.lua_CFunction>();

        static List<Lua.lua_CFunction> luaCFunctions = new List<Lua.lua_CFunction>();
        static Lua.lua_CFunction xxx = null;

        static string programa =
            "function dobledni  ()      return damedni()+damedni()  end\n" +
            "function damelen   (s)     return #s   end\n" +
            "function mul       (x,y)   return x*y  end\n" +
            "function res       (x,y)   return x-y  end\n" +
            "function sumar     (x,y)   return x+y  end\n";

        static string programa2 =
            "function main ()           \n" +
            "   if (regexIsMatch ('$INPUT', '$PATTERN')) then \n" +
            "       return 'si machea'  \n" +
            "   else                    \n" +
            "       return 'no machea'  \n" +
            "   end                     \n" +
            "end                        \n" +
            "                           \n" +
            "function fff ()            \n" +
            "   return 'hola'           \n" +
            "end                        \n" +
            "                           \n" ;

        static int regexIsMatch (IntPtr L)
        {
            //  tiene dos parámetros (vienen al reve)
            //
            var pattern = Lua.lua_tostring(L, -1);
            Lua.lua_pop(L, 1);
            var input   = Lua.lua_tostring(L, -1);
            Lua.lua_pop(L, 1);

            //  construyo el retorno
            bool isMatch = input.Contains(pattern);  //Regex.IsMatch(input, pattern);

            //  retorno
            Lua.lua_pushboolean(L, isMatch);

            //  num rets 1
            return 1;
        }

        static int damedni (IntPtr L)
        {
            Lua.lua_pushnumber(L, 28146297);
            return 1; // <- nro de valores de retorno (puedo retornar muchos, es lua)
        }
        
        static int mimoDNI (IntPtr L)
        {
            Lua.lua_pushnumber(L, 28146297);
            return 1; // <- cantidad de valores de retorno:
            // en lua se pueden retornar múltiples valores.
        }

        static void Main (string [] args)
        {
            var x = Path.GetFullPath(Lua.DLL);

            // 8 microsegs por llamado a función externa
            // (probado con 10 millones de iteraciones) 
            // en un solo procesador de 2.31 Ghz

            programa2 = programa2
                .Replace("$INPUT", @"x")
                .Replace("$PATTERN", "^[0-9]{2}");

            var L = Lua.luaL_newstate();
            Lua.luaL_openlibs(L);

            if (0 != Lua.luaL_loadstring(L, programa2) ||
                0 != Lua.lua_pcall(L, 0, 0, 0))
                mostrarErrorYSalir(L);

            var func    = new Lua.lua_CFunction(regexIsMatch);
            var keyFunc = Guid.NewGuid().ToString();
            funciones.Add(keyFunc, func);
            Lua.lua_pushcfunction(L, func);
            Lua.lua_setglobal(L, "regexIsMatch");

            var start = Environment.TickCount;
            var veces = (int) 1e4; // 10.000
            for (int i = 0; i < (int) veces; ++i)
            {
                Lua.lua_getglobal(L, "main");

                if (0 != Lua.lua_pcall(L, 0, 1, 0))
                    mostrarErrorYSalir(L);

                if (Lua.lua_isstring_b(L, -1))
                    //Console.WriteLine(Lua.lua_tostring(L, -1));
                    Lua.lua_tostring(L, -1);

                Lua.lua_pop(L, 1);
            }

            var ret = Environment.TickCount - start;
            Console.WriteLine("{0,12} llamados a función", veces);
            Console.WriteLine("{0,12} milis en total", ret);
            Console.WriteLine("{0,12} milis por llamado", (double)ret / (double)veces);
            Console.ReadLine();
            funciones.Remove(keyFunc);
            Lua.lua_close(L);
        }

        //static void Main (string [] args)
        //{
        //    var L = Lua.luaL_newstate ();
        //    Lua.luaL_openlibs(L);

        //    if (0 != Lua.luaL_loadstring(L, programa) ||
        //        0 != Lua.lua_pcall(L, 0, 0, 0))
        //        mostrarErrorYSalir(L);

        //    var start = Environment.TickCount;

        //    for (int i = 0; i < 1e7; i++)
        //    {
        //        //  Sumo numeritos
        //        //
        //        Lua.lua_getglobal(L, "sumar");

        //        if (! Lua.lua_isfunction(L, -1))
        //            mostrarErrorYSalir(L);

        //        Lua.lua_pushnumber(L,  8);
        //        Lua.lua_pushnumber(L, 54);

        //        if (0 != Lua.lua_pcall(L, 2, 1, 0))
        //            mostrarErrorYSalir(L);

        //        if (! Lua.lua_isnumberb(L, -1))
        //            mostrarErrorYSalir(L);

        //        var pipo = Lua.lua_tonumber(L, -1);
        //        Console.WriteLine(pipo);
        //        Lua.lua_pop(L, 1);

        //        //  Muestro longitud cadena
        //        //
        //        Lua.lua_getglobal(L, "damelen");

        //        if (!Lua.lua_isfunction(L, -1))
        //        {
        //            Console.WriteLine("no es una función");
        //            Environment.Exit(-1);
        //        }

        //        Lua.lua_pushstring (L, "Hola");

        //        if (0 != Lua.lua_pcall(L, 1, 1, 0))
        //            mostrarErrorYSalir(L);

        //        if (! Lua.lua_isnumberb(L, -1))
        //            mostrarErrorYSalir(L);

        //        var pipo2 = Lua.lua_tonumber(L, -1);
        //        Console.WriteLine(pipo2);
        //        Lua.lua_pop(L, 1);

        //        //  Pruebo si andan las cadenas :D
        //        //
        //        Lua.lua_pushstring  (L, "hola como te va");

        //        if (0 != Lua.lua_isstring(L, -1))
        //            Console.WriteLine(Lua.lua_tostring(L, -1));
        //        else
        //            Console.WriteLine("nop, no andan las cadenas... :o");

        //        Lua.lua_pop(L, 1);

        //        //  Pruebo función externa!!!
        //        //
        //        var f       = new Lua.lua_CFunction(damedni);
        //        var keyFunc = Guid.NewGuid().ToString();
        //        funciones.Add (keyFunc, f);
                
        //        Lua.lua_pushcfunction(L, f);
        //        Lua.lua_setglobal(L, "damedni");

        //        Lua.lua_getglobal(L, "dobledni"); // <- dobledni usa dameDNI

        //        if (! Lua.lua_isfunction(L, -1))
        //            mostrarErrorYSalir(L);

        //        if (0 != Lua.lua_pcall(L, 0, 1, 0))
        //            mostrarErrorYSalir(L);

        //        var dobledni = Lua.lua_tonumber (L, -1);
        //        Console.WriteLine(dobledni);
        //        Lua.lua_pop(L, 1);

        //        funciones.Remove(keyFunc);

        //        //  Pongo cadena y la muestro
        //        //
        //        Lua.lua_pushstring(L, "un saludito a mi vieja que me mira por tv");
                
        //        //  seteo la variable "saludo" con el valor que está en idx= -1
        //        Lua.lua_setglobal(L, "saludo");
                
        //        //  ahora la obtengo para mostrarla
        //        Lua.lua_getglobal(L, "saludo");

        //        if (! Lua.lua_isstringb(L, -1))
        //        {
        //            Console.WriteLine("no es una cadena");
        //            Environment.Exit(-1);
        //        }

        //        Console.WriteLine(Lua.lua_tostring(L, -1));
        //        Lua.lua_pop     (L, 1);
                
        //    } /* for */

        //    Console.WriteLine   ("{0} milis ", Environment.TickCount - start);
        //    Lua.lua_close       (L);
        //    Console.WriteLine   ("fin");
        //    Console.ReadLine    ();
        //}

        static void mostrarErrorYSalir (IntPtr L)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine   (Lua.lua_tostring(L, -1));
            Console.ForegroundColor = ConsoleColor.Gray;
            Lua.lua_close       (L);
            Console.ReadLine    ();
            Environment.Exit    (-1);
        }
    }
}
